﻿//_______________________________________________________________________________________________________________________
// Copy Right (c) 2010, 2011 SapiensIT Consulting GmbH, all rights reserved
//_______________________________________________________________________________________________________________________
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//_______________________________________________________________________________________________________________________
// PROJECT:     sapiens.at.SharePoint (SharePoint 2010/V4)
//_______________________________________________________________________________________________________________________
// VERSION:     2.0
//_______________________________________________________________________________________________________________________
// DESCRIPTION: 
//_______________________________________________________________________________________________________________________
// LICENSE:     Different licens Types apply to different file types:
//               - Source code files are governed by the MICROSOFT PUBLIC LICENSE (Ms-PL)
//               - Binary files are governed by MSDN CODE GALLERY BINARY LICENSE
//               - Documentation files are governed by CREATIVE COMMONS ATTRIBUTION 3.0 LICENSE
//
//               The licenses can be found at the projects source location.
//               If you do not agree, don't use it!
// 
//_______________________________________________________________________________________________________________________
// Start SharePoint Branding, visit http://www.cliggin.com! Visit us on http://www.sapiens.at! Tell your friends! 
//_______________________________________________________________________________________________________________________
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web.UI;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Sapiens.at.SharePoint.Controls;

namespace Sapiens.at.SharePoint.CustomActions
{
    /// <summary>
    /// Represents an action inside the ribbon.
    /// </summary>
    public abstract class RibbonAction
    {
        Dictionary<string, CustomActionConfig> _commands;
        /// <summary>
        /// Gets a collection of commands this action contains.
        /// </summary>
        protected IEnumerable<CustomActionConfig> Commands
        {
            get { return _commands.Values; }
        }

        List<CustomActionConfig> _applicableCommands;
        /// <summary>
        /// Gets a collection of commands that are applicable to the current context.
        /// </summary>
        internal protected IEnumerable<CustomActionConfig> ApplicableCommands
        {
            get
            {
                if (_applicableCommands == null)
                {
                    _applicableCommands = new List<CustomActionConfig>(Commands.Where(c => c.IsApplicable == null || c.IsApplicable()));
                }
                return _applicableCommands;
            }
        }

        /// <summary>
        /// Instantiates a new RibbonAction.
        /// </summary>
        public RibbonAction()
        {
            _commands = new Dictionary<string, CustomActionConfig>();
        }

        /// <summary>
        /// Registers a new command for this action.
        /// </summary>
        /// <param name="config"></param>
        protected void RegisterCommand(CustomActionConfig config)
        {
            _commands.Add(config.Command, config);
        }

        /// <summary>
        /// Returns true if the action contains a certain command.
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        internal bool HandlesCommand(string command)
        {
            return _commands.ContainsKey(GetCommand(command));
        }

        /// <summary>
        /// Calls the <see cref="CustomActionConfig.OnPreRender"/> action for each command.
        /// </summary>
        /// <param name="page"></param>
        internal void OnPreRender(Page page)
        {
            foreach (var command in ApplicableCommands.Where(ac => ac.OnPreRender != null))
            {
                command.OnPreRender(page);
            }
        }

        /// <summary>
        /// Calls the <see cref="CustomActionConfig.Callback"/> action of a certain command.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="page"></param>
        internal void RunCallback(string eventArg, Page page)
        {
            var command = GetCommand(eventArg);
            var commandConfig = _commands[command];
            if (commandConfig.Callback != null)
            {
                commandConfig.Callback(eventArg, page);
            }
        }

        /// <summary>
        /// Returns the javascript for the getGlobalCommands function.
        /// </summary>
        /// <returns></returns>
        internal virtual string GetJSGlobalCommands()
        {
            var sb = new StringBuilder();
            foreach (var command in ApplicableCommands)
            {
                sb.AppendFormat("'{0}',", command.Command);
            }
            return sb.ToString();
        }

        /// <summary>
        /// Returns the javascript for the canHandleCommand function.
        /// </summary>
        /// <returns></returns>
        internal virtual string GetJSIsEnabled(Page page)
        {
            var sb = new StringBuilder();
            foreach (var command in ApplicableCommands)
            {
                if (command.IsEnabled != null && !command.IsEnabled(page)){
                    sb.AppendFormat("if(commandId === '{0}') {{ return false; }}\n", command.Command);
                }
                else if (!string.IsNullOrEmpty(command.EnabledScript))
                {
                    sb.AppendFormat("if(commandId === '{0}') {{ {1} }}", command.Command, command.EnabledScript);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Returns the javascript for the handleCommand function.
        /// </summary>
        /// <returns></returns>
        internal virtual string GetJSCallback()
        {
            var sb = new StringBuilder();
            foreach (var command in ApplicableCommands)
            {
                if (!string.IsNullOrEmpty(command.CallbackScript) || command.Callback != null)
                {
                    var postBackScript = "";
                    if (command.Callback != null)
                    {
                        var postBackParamScript = "function getCallbackParam(){{\n {0}\n }}\n";
                        postBackParamScript = string.Format(postBackParamScript, !string.IsNullOrEmpty(command.CallbackParam) ? command.CallbackParam : "return '';");
                        postBackScript += postBackParamScript;
                        postBackScript += string.Format("__doPostBack('RibbonAction','{0}' + getCallbackParam());", command.Command);
                    }
                    sb.AppendFormat("if(commandId === '{0}') {{ {1}; {2} }}\n", command.Command, command.CallbackScript, postBackScript);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Helper method that determines, whether the current context is a listitem of a certain list.
        /// </summary>
        /// <param name="listUrls"></param>
        /// <returns></returns>
        protected static bool IsApplicableListItem(params string[] listUrls)
        {
            return SPContext.Current.FormContext != null && SPContext.Current.FormContext.FormMode == SPControlMode.Display &&
                SPContext.Current.List != null && listUrls.Contains(SPContext.Current.List.RootFolder.Url) &&
                SPContext.Current.ListItem != null;
        }

        /// <summary>
        /// Helper method that determines, whether the current context is one of a collection of lists.
        /// </summary>
        /// <param name="listUrls"></param>
        /// <returns></returns>
        protected static bool IsApplicableList(params string[] listUrls)
        {
            return SPContext.Current.List != null && listUrls.Contains(SPContext.Current.List.RootFolder.Url);
        }

        private string GetCommand(string eventArgument)
        {
            var separator = eventArgument.IndexOf(':');
            if (separator >= 0)
            {
                return eventArgument.Substring(0, separator);
            }
            else
            {
                return eventArgument;
            }
        }
    }
}
